package io.xxx.xbutler.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.xxx.xbutler.constant.Formats;
import io.xxx.xbutler.constant.Topics;
import io.xxx.xbutler.data.CallbackMapper;
import io.xxx.xbutler.domain.Callback;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.pulsar.core.PulsarTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

@Slf4j
@Service
public class CallbackService {

    @Resource
    private PulsarTemplate<Long> pulsarTemplate;

    @Resource
    private CallbackMapper callbackMapper;

    @Value("${callback.data.directory:cdata}")
    private String cdataDirectory;

    public void resend(List<Long> ids, List<Integer> types, List<Integer> status) {
        LambdaQueryWrapper<Callback> wrapper = new LambdaQueryWrapper<>();
        if (!ObjectUtils.isEmpty(types)) {
            wrapper.in(Callback::getType, types);
        }
        if (!ObjectUtils.isEmpty(ids)) {
            wrapper.in(Callback::getId, ids);
        }
        if (!ObjectUtils.isEmpty(status)) {
            wrapper.in(Callback::getStatus, status);
        }
        List<Callback> callbacks = callbackMapper.selectList(wrapper);
        for (Callback callback : callbacks) {
            pulsarTemplate.send(Topics.CALLBACK, callback.getId());
        }
    }

    public void reload(List<LocalDate> dates, Boolean resend) throws IOException {
        for (LocalDate date : dates) {
            Path path = Paths.get(cdataDirectory, date.format(Formats.COMPACT_DATE_FORMATTER));
            if (!Files.exists(path)) {
                continue;
            }
            try (BufferedReader reader = Files.newBufferedReader(path)) {
                reader.lines().forEach(line -> {
                    if (!StringUtils.hasText(line)) {
                        return;
                    }
                    // id(14) + sign(32) + content length(8) + context
                    long id = Long.parseLong(line.substring(0, 14));
                    String sign = line.substring(14, 46);
                    long length = Long.parseLong(line.substring(46, 54));
                    String context = line.substring(54);
                    if (context.length() != length) {
                        log.error("数据长度不匹配[{}]", line);
                        return;
                    }
                    JSONObject json = JSON.parseObject(context);
                    Callback callback = new Callback()
                            .setId(id)
                            .setMerchantNo(json.getString("vcMerchantNo"))
                            .setType(json.getInteger("nType"))
                            .setSerialNo(json.getString("vcSerialNo"))
                            .setRobotId(json.getString("vcRobotWxId"))
                            .setRobotSerialNo(json.getString("vcRobotSerialNo"))
                            .setCode(json.getInteger("nResult"))
                            .setMessage(json.getString("vcResult"))
                            .setTimestamp(LocalDateTime.ofInstant(json.getInstant("nTimeStamp"), ZoneOffset.systemDefault()))
                            .setContext(JSON.parseObject(context))
                            .setData(json.get("Data"))
                            .setSign(sign)
                            .setCreatedTime(LocalDateTime.now());
                    boolean exists = isExists(callback.getId());
                    if (!exists) {
                        callbackMapper.insert(callback);
                        if (resend) {
                            pulsarTemplate.send(Topics.CALLBACK, callback.getId());
                        }
                    }
                });
            }
        }
    }

    private boolean isExists(Long callbackId) {
        LambdaQueryWrapper<Callback> wrapper = new LambdaQueryWrapper<Callback>()
                .eq(Callback::getId, callbackId);
        return callbackMapper.exists(wrapper);
    }
}
